<template>
  <div class="chat-container">
    <div class="chat-header">
      <h3>{{ requestAnswerGroupName !== null ? requestAnswerGroupName : '新对话' }}</h3>
    </div>

    <div class="messages" ref="messagesRef">
      <Message
          v-for="(message, index) in messages"
          :key="index"
          :message="message"
      />
    </div>


    <div class="input-area">
      <el-input
          placeholder="有问题，尽管问，shift+enter换行"
          v-model="inputMessage"
          type="textarea"
          :rows="5"
          :style="{
            '--el-input-border-color': 'transparent',
            '--el-input-hover-border-color': 'transparent',
            '--el-input-focus-border-color': 'transparent'
          }"
          @keydown.enter.exact.prevent="sendMsg"
      />
      <div>
        <div class="actions-right" style="float: left;padding-left: 20px">
          <el-select
              v-model="selectModel"
              placeholder="选择模型"
              style="width: 150px;"
              @change="selectModelChange"
              :disabled="!canSelectModelFlag"
              v-if="currentSelectType === 'llmModel'"
          >
            <el-option v-for="item in llmModelData"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id">
              <span>{{ item.name }}</span> &nbsp;
              <el-tag v-if="item.type === 0" type="primary">对话</el-tag>
              <el-tag v-else-if="item.type === 1" type="warning">文生图</el-tag>
              <el-tag v-else-if="item.type === 2" type="success">文生视频</el-tag>
              <el-tag v-else-if="item.type === 3" type="danger">文生语音</el-tag>
            </el-option>
          </el-select>
          <el-select
              v-model="selectWorkflow"
              placeholder="选择流程"
              style="width: 150px;"
              :disabled="!canSelectModelFlag"
              v-else
          >
            <el-option v-for="item in workflowData"
                       :key="item.id"
                       :label="item.name"
                       :value="item.id"
            />
          </el-select>
          <el-switch
              v-model="switchDeepThinking"
              :disabled="!supportDeepThinking"
              inline-prompt
              size="large"
              style="padding-bottom: 7px"
              active-text="R·深度思考"
              inactive-text="R·深度思考"
          />
        </div>
        <div class="actions-right" style="float: right;padding-right: 20px">
          <el-button type="text" :disabled="!supportImageUpload">
            <el-icon size="large" style="padding-bottom: 7px">
              <Picture/>
            </el-icon>
          </el-button>
          <el-button type="text" :disabled="!supportFileUpload">
            <el-icon size="large" style="padding-bottom: 7px">
              <FolderChecked/>
            </el-icon>
          </el-button>
          <el-button
              size="small"
              type="primary"
              @click="sendMsg"
              :loading-icon="Eleme"
              :loading="!canSendFlag"
              :disabled="!canSendFlag">发送
            <el-icon style="margin-left: 5px">
              <Promotion/>
            </el-icon>
          </el-button>
        </div>
      </div>

    </div>
  </div>
</template>

<script setup>
import {Eleme, FolderChecked, Promotion} from "@element-plus/icons-vue";
import Message from './Message.vue'
import {
  aiAppId,
  canSelectModelFlag,
  canSendFlag,
  currentSelectType,
  historyData, initNewChat,
  isPreviewFlag,
  llmModelData,
  messages,
  messagesRef,
  previewReqData,
  requestAnswerGroupCode,
  requestAnswerGroupName,
  selectModel,
  selectWorkflow,
  sendMessageNew,
  supportDeepThinking,
  supportFileUpload,
  supportImageUpload,
  switchDeepThinking,
  workflowData,
} from "@/api/ai/ai.js";
import {parseTime} from "@/utils/common.js";
import {listAiEnableModel} from "@/api/ai/aiModel.js";
import {listAllRelease} from "@/api/ai/aiFlow.js";
import useUserStore from "@/store/modules/user.js";
import {initSSEInstance} from "@/api/common.js";

const inputMessage = ref('')
const {proxy} = getCurrentInstance();
const userStore = useUserStore()
let eventSourceInstance = null
let isProcessing = false;
const messageQueue = [];

function sendMsg() {
  if (!canSendFlag.value) {
    return;
  }
  // 输入内容为空，不发送
  if (!inputMessage.value.trim()) {
    return
  }
  // 未回答完之前，不能再次发送
  canSendFlag.value = false
  // 添加用户的问题到聊天框里面
  buildMessage(inputMessage.value, null, true, false)

  const sendMessageText = inputMessage.value;
  inputMessage.value = ''
  const useDeepThing = switchDeepThinking.value !== undefined ? switchDeepThinking.value : false

  // 回答的问题输出
  const streamingText = ref('回答中请稍等...')
  const reactionStreamText = ref('')
  // 构建回答AI的消息
  buildMessage(streamingText, reactionStreamText, false, useDeepThing)
  scrollToBottom();

  const data = {
    "message": sendMessageText,
    "modelId": selectModel.value,
    "useDeepThing": useDeepThing,
    "requestAnswerGroupCode": requestAnswerGroupCode.value,
    "requestAnswerGroupName": requestAnswerGroupName.value,
    "hasPreview": isPreviewFlag.value,
    "aiAppsId": aiAppId.value,
    "workflowId": selectWorkflow.value,
    // 预览模式下的数据
    "previewParam": previewReqData.value
  }
  // 发送消息前，创建sse连接，保证发送前 sse连接已经建立
  if (eventSourceInstance === null || eventSourceInstance.readyState === EventSource.CLOSED) {
    // 未连接或离线的时候 进行sse连接
    eventSourceInstance = initSSEInstance("ai", "admin", userStore.name)
  }
  // 发送消息
  sendMessageNew(data)
  onMessageListener(streamingText, reactionStreamText, useDeepThing)
}

function buildMessage(streamingText, reactionStreamText, isUser, useDeepThing) {
  messages.value.push({
    text: streamingText,
    reactionText: reactionStreamText,
    isUser: isUser,
    isReaction: useDeepThing,
    time: parseTime(new Date())
  });
}

async function onMessageListener(streamingText, reactionStreamText, useDeepThing) {
  // 消息监听接收消息
  eventSourceInstance.onmessage = function (event) {
    console.log('ai-收到消息：' + event.data);
    messageQueue.push(event.data); // 将消息加入队列
    dealWithSSEMessage(streamingText, reactionStreamText, useDeepThing)
  }

  // 链接监听，异常监听
  eventSourceInstance.onerror = (error) => {
    console.error('ai-SSE与服务端连接发生错误', err);
    if (eventSourceInstance === null || eventSourceInstance.readyState === EventSource.CLOSED) {
      eventSourceInstance = initSSEInstance("ai", "admin", userStore.name)
    }
  }
}

function handleMessage(eventData, streamingText, reactionStreamText, useDeepThing) {
  const respDataObj = JSON.parse(eventData)
  if (respDataObj.status === 'start') {
    return
  }
  if (requestAnswerGroupCode.value === null) {
    historyData.value.unshift({
      "requestAnswerGroupCode": respDataObj.requestAnswerGroupCode,
      "requestAnswerGroupName": respDataObj.requestAnswerGroupName
    })
  }
  requestAnswerGroupCode.value = respDataObj.requestAnswerGroupCode
  requestAnswerGroupName.value = respDataObj.requestAnswerGroupName
  const reasonContent = respDataObj.reasoningContent;
  const content = respDataObj.content;
  // 思考过程
  if (reasonContent) {
    if (useDeepThing) {
      reactionStreamText.value += reasonContent
      streamingText.value = ''
    } else {
      streamingText.value = "回答中请稍等..."
    }
  }
  if (content && streamingText.value === '回答中请稍等...') {
    streamingText.value = ''
  }
  // 回答内容
  if (content) {
    streamingText.value += content
  }
  if (respDataObj.status === 'done') {
    canSendFlag.value = true
  }
  scrollToBottom()
}

function dealWithSSEMessage(streamingText, reactionStreamText, useDeepThing) {
  if (isProcessing || messageQueue.length === 0) {
    return
  }
  isProcessing = true;
  const data = messageQueue.shift();
  // 模拟异步处理（如需要等待前一条的结果）
  handleMessage(data, streamingText, reactionStreamText, useDeepThing);
  isProcessing = false;
  dealWithSSEMessage(streamingText, reactionStreamText, useDeepThing); // 处理下一条
}

const scrollToBottom = () => {
  nextTick(() => {
    messagesRef.value.scrollTop = messagesRef.value.scrollHeight
    const codeElements = document.querySelectorAll('.markdown-body pre code');
    codeElements.forEach(codeElement => {
      codeElement.scrollTop = codeElement.scrollHeight;
    })
  })
}

onMounted(() => {
  scrollToBottom()
})

function initModel() {
  // 0-对话  1：生图 2:视频  3：语音  4：向量  5：重排
  const queryType = [0, 1]
  listAiEnableModel(queryType).then(res => {
    llmModelData.value = res.data
    if (selectModel.value === null) {
      selectModel.value = llmModelData.value[0].id
    }
    supportDeepThinking.value = llmModelData.value[0].supportDeepThinking
  })
}

function initWorkflow() {
  listAllRelease().then(response => {
    workflowData.value = response.data;
  })
}

function selectModelChange(model) {
  llmModelData.value.forEach(item => {
    if (item.id === model) {
      supportDeepThinking.value = item.supportDeepThinking
      switchDeepThinking.value = false
    }
  })
}

function setupCopyCode() {
  // 等待 DOM 更新
  setTimeout(() => {
    // 复制按钮监听事件
    const copyButtons = document.querySelectorAll('.copy-button');
    copyButtons.forEach(button => {
      button.onclick = function () {
        const code = decodeURIComponent(button.getAttribute('data-code'));
        copyMessageText(code);
      }
    });
  }, 0);
}


function copyMessageText(text) {
  // 复制answer
  if (text !== null) {
    navigator.clipboard.writeText(text).then(() => {
      proxy.$modal.msgSuccess("复制成功");
    }).catch(() => {
      proxy.$modal.msgError("复制失败");
    });
  } else {
    proxy.$modal.msgError("内容为空，复制失败");
  }
}

initNewChat()
initWorkflow()
initModel()
</script>

<style scoped>

.input-area {
  margin: 0 auto;
  width: 60%;
  border: 1px #cccccc solid;
  padding: 5px 5px;
  border-radius: 15px;
}

.chat-container {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.chat-header {
  padding: 15px 20px;
}

.messages {
  flex-grow: 1;
  overflow-y: auto;
  padding: 20px;
}

.hint {
  font-size: 12px;
  color: #999;
  margin-bottom: 5px;
}

.download-hint {
  font-size: 12px;
  color: #1890ff;
  margin-bottom: 10px;
  cursor: pointer;
}

.actions-right {
  margin-top: 10px;
  display: flex;
  gap: 10px;
  justify-content: right;
}
</style>